library(dplyr)
library(sf)
library(tidyverse)
library(leaflet)
library(sf)
library(leaflet.providers)
library(RColorBrewer)
library(tigris)

Dot Density Plot

# education_url <- "https://github.com/dyerlab/ENVS-Lectures/raw/master/data/edu_attainment-shp.zip"
# 
# file <- tempfile(pattern = "edu", tmpdir = ".", fileext = ".zip")
# file
# 
# download.file(education_url, destfile = file)
# unzip(file, exdir = ".")
# 
# 
# points <- st_read("edu_attainment-shp")

setwd("~/Spring2021/GISinR/GISinR")
The working directory was changed to C:/Users/Charis/Documents/Spring2021/GISinR/GISinR inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
points <- st_read("edu_attainment-shp")
Reading layer `edu_attainment' from data source `C:\Users\Charis\Documents\Spring2021\GISinR\GISinR\edu_attainment-shp' using driver `ESRI Shapefile'
Simple feature collection with 15745 features and 1 field
geometry type:  POINT
dimension:      XY
bbox:           xmin: -77.59891 ymin: 37.44779 xmax: -77.38568 ymax: 37.60228
geographic CRS: WGS 84

Convert education levels to factor - this allows us to use colorFactor() to create our color palette

points$education <- factor(points$education, levels = c("No HS diploma", "HS, no Bachelors", "Bachelors" , "Post-Bachelors"  )) 

Create color palette

factpal <- colorFactor(brewer.pal(n = 4, name = "RdBu"), points$education) #used to color categorical data

Create dot density plot

leaflet(points) %>% 
  addProviderTiles(providers$CartoDB.Positron)%>% #add provider tiles
  addCircles(stroke = FALSE,  fillOpacity = 1, #add points
              color = ~factpal(education)) %>% #color based on educational attainment
  addLegend(pal = factpal, values = ~education, title = "Education Attainment")%>% #add legend
  addScaleBar(position = "bottomright") #add scale bar

Choropleth plot

load in the census tract data

tracts <- tracts("VA", "Richmond city") %>%
  st_transform(4326)
Using FIPS code '51' for state 'VA'
Using FIPS code '760' for 'Richmond city'

Data Prep

edu_tracts <- tracts %>%
  st_buffer(dist = 0) %>% # buffer by 0 to avoid error message
  st_intersection(points) # intersect the point data with the tract polygons
edu_tracts %>%
  group_by(NAME, education) %>% # group by tract name and education level
  tally() -> tally # tally() counts the number of rows for the groups, so output is one row for every attainment level for each tract (so if a tract has all 4 attainment levels, there are 4 rows of data for that tract)
tally <- as.data.frame(tally) # converted to data.frame to be able to drop the geometry because the `pivot_wider()` function would not work the way I wanted it to when the geometry was present

tally <- tally %>%
  select(NAME, education, n)%>% # do not want the geometry 
  pivot_wider(names_from = education, values_from = n) # pivot the table so that instead of having multiple rows per tract, you have one row per tract with a column for each attainment level

tally[is.na(tally)] <- 0 # define NA values as zero

tally

Create attainment metric for choropleth

tally <- tally %>%
  mutate(edu = (((`No HS diploma` * 1) + (`HS, no Bachelors` * 2) + (`Bachelors` * 3) + (`Post-Bachelors` * 4))/
                  (`No HS diploma`  + `HS, no Bachelors` + `Bachelors` + `Post-Bachelors`)))

# I created a column, edu, and did a weighted average for each row. So 'No HS diploma' was weighted as 1, 'HS, no Bachelors' as 2, ect. 

# I used this new column as my average education attainment value to color my polygons
tally %>%
  select(NAME, edu) -> tally # no longer need the individual count data

Join the education data back with the tract data

tracts %>%
  left_join(tally, by = "NAME") -> tracts

Create the palette

pal <- colorNumeric(
  palette = "RdBu",
  domain = tracts$edu) # This time I want a continuos palatte, so I used `colorNumeric()`

Make the choropleth map

leaflet(tracts) %>%
  addProviderTiles(providers$CartoDB.Positron)%>% # add provider tiles
  addPolygons( fillOpacity = 1, # add tract polygons
               fillColor = ~pal(edu), smoothFactor = 0.2, # fill color based on the calculated 'edu' metric
               color = "grey", 
               opacity = 1,
               weight = 1) %>%
  addLegend(pal = pal, values = ~edu, title = "Education Attainment") # add legend

I did not like this legend, as it’s unclear what the numbers mean. With some googling I found a solution

labels <-c("No HS diploma (1)", "HS, no Bachelors (2)",
           "Bachelors (3)" , "Post-Bachelors (4)"  ) # define the labels for the legend
leaflet(tracts) %>%
  addProviderTiles(providers$CartoDB.Positron)%>% # add provider tiles
  addPolygons( fillOpacity = 1, # add tract polygons
               fillColor = ~pal(edu), smoothFactor = 0.2, # fill color based on the calculated 'edu' metric
               color = "grey", 
               opacity = 1,
               weight = 1) %>%
  addLegend(pal = pal, values = ~edu, 
            opacity = 1,
            title = "Education Attainment",
            labFormat = function(type, cuts, p) {  # Here's the trick
              paste0(labels)
            })

That looks better, I think

Combine the maps

Final map

LS0tDQp0aXRsZTogIkxlYWZsZXQgSG9tZXdvcmsgS2V5Ig0KYXV0aG9yOiAiQ2hhcmlzIERlYWR3eWxlciINCmRhdGU6ICIzLzE1LzIwMjEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShsZWFmbGV0LnByb3ZpZGVycykNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeSh0aWdyaXMpDQpgYGANCg0KIyMjIERvdCBEZW5zaXR5IFBsb3QNCmBgYHtyfQ0KIyBlZHVjYXRpb25fdXJsIDwtICJodHRwczovL2dpdGh1Yi5jb20vZHllcmxhYi9FTlZTLUxlY3R1cmVzL3Jhdy9tYXN0ZXIvZGF0YS9lZHVfYXR0YWlubWVudC1zaHAuemlwIg0KIyANCiMgZmlsZSA8LSB0ZW1wZmlsZShwYXR0ZXJuID0gImVkdSIsIHRtcGRpciA9ICIuIiwgZmlsZWV4dCA9ICIuemlwIikNCiMgZmlsZQ0KIyANCiMgZG93bmxvYWQuZmlsZShlZHVjYXRpb25fdXJsLCBkZXN0ZmlsZSA9IGZpbGUpDQojIHVuemlwKGZpbGUsIGV4ZGlyID0gIi4iKQ0KIyANCiMgDQojIHBvaW50cyA8LSBzdF9yZWFkKCJlZHVfYXR0YWlubWVudC1zaHAiKQ0KYGBgDQoNCkNvbnZlcnQgZWR1Y2F0aW9uIGxldmVscyB0byBmYWN0b3IgLSB0aGlzIGFsbG93cyB1cyB0byB1c2UgYGNvbG9yRmFjdG9yKClgIHRvIGNyZWF0ZSBvdXIgY29sb3IgcGFsZXR0ZQ0KYGBge3J9DQpwb2ludHMkZWR1Y2F0aW9uIDwtIGZhY3Rvcihwb2ludHMkZWR1Y2F0aW9uLCBsZXZlbHMgPSBjKCJObyBIUyBkaXBsb21hIiwgIkhTLCBubyBCYWNoZWxvcnMiLCAiQmFjaGVsb3JzIiAsICJQb3N0LUJhY2hlbG9ycyIgICkpIA0KYGBgDQoNCkNyZWF0ZSBjb2xvciBwYWxldHRlDQpgYGB7cn0NCmZhY3RwYWwgPC0gY29sb3JGYWN0b3IoYnJld2VyLnBhbChuID0gNCwgbmFtZSA9ICJSZEJ1IiksIHBvaW50cyRlZHVjYXRpb24pICN1c2VkIHRvIGNvbG9yIGNhdGVnb3JpY2FsIGRhdGENCmBgYA0KDQoNCkNyZWF0ZSBkb3QgZGVuc2l0eSBwbG90DQpgYGB7cn0NCmxlYWZsZXQocG9pbnRzKSAlPiUgDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pJT4lICNhZGQgcHJvdmlkZXIgdGlsZXMNCiAgYWRkQ2lyY2xlcyhzdHJva2UgPSBGQUxTRSwgIGZpbGxPcGFjaXR5ID0gMSwgI2FkZCBwb2ludHMNCiAgICAgICAgICAgICAgY29sb3IgPSB+ZmFjdHBhbChlZHVjYXRpb24pKSAlPiUgI2NvbG9yIGJhc2VkIG9uIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQNCiAgYWRkTGVnZW5kKHBhbCA9IGZhY3RwYWwsIHZhbHVlcyA9IH5lZHVjYXRpb24sIHRpdGxlID0gIkVkdWNhdGlvbiBBdHRhaW5tZW50IiklPiUgI2FkZCBsZWdlbmQNCiAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKSAjYWRkIHNjYWxlIGJhcg0KYGBgDQoNCiMjIyBDaG9yb3BsZXRoIHBsb3QNCg0KbG9hZCBpbiB0aGUgY2Vuc3VzIHRyYWN0IGRhdGENCmBgYHtyfQ0KdHJhY3RzIDwtIHRyYWN0cygiVkEiLCAiUmljaG1vbmQgY2l0eSIpICU+JQ0KICBzdF90cmFuc2Zvcm0oNDMyNikNCmBgYA0KDQpEYXRhIFByZXANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQplZHVfdHJhY3RzIDwtIHRyYWN0cyAlPiUNCiAgc3RfYnVmZmVyKGRpc3QgPSAwKSAlPiUgIyBidWZmZXIgYnkgMCB0byBhdm9pZCBlcnJvciBtZXNzYWdlDQogIHN0X2ludGVyc2VjdGlvbihwb2ludHMpICMgaW50ZXJzZWN0IHRoZSBwb2ludCBkYXRhIHdpdGggdGhlIHRyYWN0IHBvbHlnb25zDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmVkdV90cmFjdHMgJT4lDQogIGdyb3VwX2J5KE5BTUUsIGVkdWNhdGlvbikgJT4lICMgZ3JvdXAgYnkgdHJhY3QgbmFtZSBhbmQgZWR1Y2F0aW9uIGxldmVsDQogIHRhbGx5KCkgLT4gdGFsbHkgIyB0YWxseSgpIGNvdW50cyB0aGUgbnVtYmVyIG9mIHJvd3MgZm9yIHRoZSBncm91cHMsIHNvIG91dHB1dCBpcyBvbmUgcm93IGZvciBldmVyeSBhdHRhaW5tZW50IGxldmVsIGZvciBlYWNoIHRyYWN0IChzbyBpZiBhIHRyYWN0IGhhcyBhbGwgNCBhdHRhaW5tZW50IGxldmVscywgdGhlcmUgYXJlIDQgcm93cyBvZiBkYXRhIGZvciB0aGF0IHRyYWN0KQ0KDQpgYGANCg0KYGBge3J9DQp0YWxseSA8LSBhcy5kYXRhLmZyYW1lKHRhbGx5KSAjIGNvbnZlcnRlZCB0byBkYXRhLmZyYW1lIHRvIGJlIGFibGUgdG8gZHJvcCB0aGUgZ2VvbWV0cnkgYmVjYXVzZSB0aGUgYHBpdm90X3dpZGVyKClgIGZ1bmN0aW9uIHdvdWxkIG5vdCB3b3JrIHRoZSB3YXkgSSB3YW50ZWQgaXQgdG8gd2hlbiB0aGUgZ2VvbWV0cnkgd2FzIHByZXNlbnQNCg0KdGFsbHkgPC0gdGFsbHkgJT4lDQogIHNlbGVjdChOQU1FLCBlZHVjYXRpb24sIG4pJT4lICMgZG8gbm90IHdhbnQgdGhlIGdlb21ldHJ5IA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZWR1Y2F0aW9uLCB2YWx1ZXNfZnJvbSA9IG4pICMgcGl2b3QgdGhlIHRhYmxlIHNvIHRoYXQgaW5zdGVhZCBvZiBoYXZpbmcgbXVsdGlwbGUgcm93cyBwZXIgdHJhY3QsIHlvdSBoYXZlIG9uZSByb3cgcGVyIHRyYWN0IHdpdGggYSBjb2x1bW4gZm9yIGVhY2ggYXR0YWlubWVudCBsZXZlbA0KDQp0YWxseVtpcy5uYSh0YWxseSldIDwtIDAgIyBkZWZpbmUgTkEgdmFsdWVzIGFzIHplcm8NCg0KdGFsbHkNCmBgYA0KDQpDcmVhdGUgYXR0YWlubWVudCBtZXRyaWMgZm9yIGNob3JvcGxldGgNCg0KYGBge3J9DQp0YWxseSA8LSB0YWxseSAlPiUNCiAgbXV0YXRlKGVkdSA9ICgoKGBObyBIUyBkaXBsb21hYCAqIDEpICsgKGBIUywgbm8gQmFjaGVsb3JzYCAqIDIpICsgKGBCYWNoZWxvcnNgICogMykgKyAoYFBvc3QtQmFjaGVsb3JzYCAqIDQpKS8NCiAgICAgICAgICAgICAgICAgIChgTm8gSFMgZGlwbG9tYWAgICsgYEhTLCBubyBCYWNoZWxvcnNgICsgYEJhY2hlbG9yc2AgKyBgUG9zdC1CYWNoZWxvcnNgKSkpDQoNCiMgSSBjcmVhdGVkIGEgY29sdW1uLCBlZHUsIGFuZCBkaWQgYSB3ZWlnaHRlZCBhdmVyYWdlIGZvciBlYWNoIHJvdy4gU28gJ05vIEhTIGRpcGxvbWEnIHdhcyB3ZWlnaHRlZCBhcyAxLCAnSFMsIG5vIEJhY2hlbG9ycycgYXMgMiwgZWN0LiANCg0KIyBJIHVzZWQgdGhpcyBuZXcgY29sdW1uIGFzIG15IGF2ZXJhZ2UgZWR1Y2F0aW9uIGF0dGFpbm1lbnQgdmFsdWUgdG8gY29sb3IgbXkgcG9seWdvbnMNCmBgYA0KDQpgYGB7cn0NCnRhbGx5ICU+JQ0KICBzZWxlY3QoTkFNRSwgZWR1KSAtPiB0YWxseSAjIG5vIGxvbmdlciBuZWVkIHRoZSBpbmRpdmlkdWFsIGNvdW50IGRhdGENCmBgYA0KDQpKb2luIHRoZSBlZHVjYXRpb24gZGF0YSBiYWNrIHdpdGggdGhlIHRyYWN0IGRhdGENCg0KYGBge3J9DQp0cmFjdHMgJT4lDQogIGxlZnRfam9pbih0YWxseSwgYnkgPSAiTkFNRSIpIC0+IHRyYWN0cw0KYGBgDQoNCkNyZWF0ZSB0aGUgcGFsZXR0ZQ0KDQpgYGB7cn0NCnBhbCA8LSBjb2xvck51bWVyaWMoDQogIHBhbGV0dGUgPSAiUmRCdSIsDQogIGRvbWFpbiA9IHRyYWN0cyRlZHUpICMgVGhpcyB0aW1lIEkgd2FudCBhIGNvbnRpbnVvcyBwYWxhdHRlLCBzbyBJIHVzZWQgYGNvbG9yTnVtZXJpYygpYA0KYGBgDQoNCk1ha2UgdGhlIGNob3JvcGxldGggbWFwDQoNCmBgYHtyfQ0KbGVhZmxldCh0cmFjdHMpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSU+JSAjIGFkZCBwcm92aWRlciB0aWxlcw0KICBhZGRQb2x5Z29ucyggZmlsbE9wYWNpdHkgPSAxLCAjIGFkZCB0cmFjdCBwb2x5Z29ucw0KICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChlZHUpLCBzbW9vdGhGYWN0b3IgPSAwLjIsICMgZmlsbCBjb2xvciBiYXNlZCBvbiB0aGUgY2FsY3VsYXRlZCAnZWR1JyBtZXRyaWMNCiAgICAgICAgICAgICAgIGNvbG9yID0gImdyZXkiLCANCiAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5lZHUsIHRpdGxlID0gIkVkdWNhdGlvbiBBdHRhaW5tZW50IikgIyBhZGQgbGVnZW5kDQpgYGANCg0KSSBkaWQgbm90IGxpa2UgdGhpcyBsZWdlbmQsIGFzIGl0J3MgdW5jbGVhciB3aGF0IHRoZSBudW1iZXJzIG1lYW4uIFdpdGggc29tZSBnb29nbGluZyBJIGZvdW5kIGEgc29sdXRpb24NCg0KYGBge3J9DQpsYWJlbHMgPC1jKCJObyBIUyBkaXBsb21hICgxKSIsICJIUywgbm8gQmFjaGVsb3JzICgyKSIsDQogICAgICAgICAgICJCYWNoZWxvcnMgKDMpIiAsICJQb3N0LUJhY2hlbG9ycyAoNCkiICApICMgZGVmaW5lIHRoZSBsYWJlbHMgZm9yIHRoZSBsZWdlbmQNCmBgYA0KDQpgYGB7cn0NCmxlYWZsZXQodHJhY3RzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbiklPiUgIyBhZGQgcHJvdmlkZXIgdGlsZXMNCiAgYWRkUG9seWdvbnMoIGZpbGxPcGFjaXR5ID0gMSwgIyBhZGQgdHJhY3QgcG9seWdvbnMNCiAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH5wYWwoZWR1KSwgc21vb3RoRmFjdG9yID0gMC4yLCAjIGZpbGwgY29sb3IgYmFzZWQgb24gdGhlIGNhbGN1bGF0ZWQgJ2VkdScgbWV0cmljDQogICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IiwgDQogICAgICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgICAgIHdlaWdodCA9IDEpICU+JQ0KICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+ZWR1LCANCiAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgdGl0bGUgPSAiRWR1Y2F0aW9uIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gZnVuY3Rpb24odHlwZSwgY3V0cywgcCkgeyAgIyBIZXJlJ3MgdGhlIHRyaWNrDQogICAgICAgICAgICAgIHBhc3RlMChsYWJlbHMpDQogICAgICAgICAgICB9KQ0KYGBgDQpUaGF0IGxvb2tzIGJldHRlciwgSSB0aGluaw0KDQojIyMgQ29tYmluZSB0aGUgbWFwcw0KDQpgYGB7cn0NCg0KbGVhZmxldCgpICU+JSAjIEkgZGVjaWRlZCB0byBkZWZpbmUgYnkgZGF0YSBieSBsYXllciBiZWNhdXNlIEkgaGF2ZSBtdWx0aXBsZSBkYXRhIHNldHMNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lICMgQWRkIHByb3ZpZGVyIHRpbGVzDQogIGFkZFBvbHlnb25zKGRhdGEgPSB0cmFjdHMsICMgSSBkZWNpZGVkIHRvIHBsb3QgdGhlIHRyYWN0cyBvbiB0aGUgZG90IGRlbnNpdHkgbWFwDQogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSwNCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLA0KICAgICAgICAgICAgICBncm91cCA9ICJDaXJjbGUiICMgTmVlZCB0byBncm91cHMsIDEgZm9yIGRlbnNpdHkgcGxvdCBhbmQgMSBmb3IgY2hvcm9wbGV0aA0KICAgICAgICAgICAgICApICAlPiUNCiAgYWRkQ2lyY2xlcyhkYXRhID0gcG9pbnRzLA0KICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFLCAgZmlsbE9wYWNpdHkgPSAxLCAjcGxvdCB0aGUgY2lyY2xlcyBvbiB0b3Agb2YgdGhlIHRyYWN0cw0KICAgICAgICAgICAgIGNvbG9yID0gfmZhY3RwYWwoZWR1Y2F0aW9uKSwNCiAgICAgICAgICAgICBncm91cCA9ICJDaXJjbGUiICMgRGVmaW5lIGdyb3VwDQogICAgICAgICAgICAgKSAlPiUNCiAgYWRkTGVnZW5kKGRhdGEgPSBwb2ludHMsDQogICAgICAgICAgICBwYWwgPSBmYWN0cGFsLCAjIEFkZCBsZWdlbmQgZm9yIGRvdCBkZW5zaXR5IHBsb3QNCiAgICAgICAgICAgIHZhbHVlcyA9IH5lZHVjYXRpb24sDQogICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgIHRpdGxlID0gIkVkdWNhdGlvbmFsIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgZ3JvdXAgPSAiQ2lyY2xlIiAjIERlZmluZSBncm91cCBmb3IgbGVnZW5kDQogICAgICAgICAgICApICU+JQ0KICBncm91cE9wdGlvbnMoIkNpcmNsZSIsIHpvb21MZXZlbHMgPSAxOjEyICMgRGVmaW5lIHRoZSB6b29tIGxldmVscyBmb3IgdGhlIGRvdCBkZW5zaXR5IHBsb3QgKGRvdHMgd2lsbCBvbmx5IGJ5IHZpc2libGUgYmV0d2VlbiB6b29tIGxldmVscyAxIGFuZCAxMikNCiAgICAgICAgICAgICAgICkgJT4lDQogIGFkZFBvbHlnb25zKCBkYXRhID0gdHJhY3RzLCAjIEZpcnN0IGxheWVyIG9mIHRoZSBjaG9yb3BsZXRoIG1hcCwgdHJhY3QgcG9seWdvbnMNCiAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjc1LA0KICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChlZHUpLCBzbW9vdGhGYWN0b3IgPSAwLjIsICMgQ29sb3IgZGVmaW5lZCBieSBhdHRhaW5tZW50IG1ldHJpYw0KICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgICAgIHdlaWdodCA9IDEsDQogICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZSgiQXR0YWlubWVudDoiLCByb3VuZChlZHUsIGRpZ2l0cyA9IDIpKSwgIyBBZGRpbmcgYSBsYWJlbCB3aXRoIHRoZSBhdHRhaW5tZW50IG1ldHJpYywgcm91bmRpbmcgdG8gMiBkaWdpdHMgYWZ0ZXIgdGhlIGRlY2ltYWwNCiAgICAgICAgICAgICAgIGdyb3VwID0gIkNob3JvIiAjIENhbGxlZCBteSBzZWNvbmQgZ3JvdXAgIkNob3JvIg0KICAgICAgICAgICAgICAgKSAlPiUNCiAgYWRkTGVnZW5kKGRhdGEgPSB0cmFjdHMsDQogICAgICAgICAgICBwYWwgPSBwYWwsICMgQWRkIGxlZ2VuZCBmb3IgY2hvcm9wbGV0aCBwbG90DQogICAgICAgICAgICB2YWx1ZXMgPSB+ZWR1LA0KICAgICAgICAgICAgb3BhY2l0eSA9IC43NSwNCiAgICAgICAgICAgIHRpdGxlID0gIkVkdWNhdGlvbmFsIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gZnVuY3Rpb24odHlwZSwgY3V0cywgcCkgeyAgIyBIZXJlJ3MgdGhlIHRyaWNrIGFnYWluDQogICAgICAgICAgICAgIHBhc3RlMChsYWJlbHMpDQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgZ3JvdXAgPSAiQ2hvcm8iICMgQWRkIHRvIGNob3JvcGxldGggZ3JvdXANCiAgICAgICAgICAgICkgJT4lDQogZ3JvdXBPcHRpb25zKCJDaG9ybyIsIHpvb21MZXZlbHMgPSAxMzoyMCAgIyBEZWZpbmUgbGV2ZWxzIGZvciB0aGUgY2hvcm9wbGV0aCBtYXAgKGNob3JvcGxldGggcG9seWdvbnMgd2lsbCBvbmx5IGJlIHZpc2JsZSBiZXR3ZWVuIHpvb20gbGV2bHMgMTMgYW5kIDIwKQ0KICAgICAgICAgICAgICApICU+JQ0KICBhZGRTY2FsZUJhcihwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpICMgQWRkIHNjYWxlIGJhci4gU2NhbGUgYmFyIGRvZXMgbm90IG5lZWQgYSBncm91cCBiZWNhdXNlIEkgd2FudCBpdCB2aXNpYmxlIGF0IGFsbCB6b29tIGxldmVscw0KIA0KDQoNCmBgYA0KDQpGaW5hbCBtYXANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=